package com.zby.springbootdemo.exception;

import org.omg.CORBA.SystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @ControllerAdvice + @ExceptionHandler 进行全局的 Controller 层异常处理
 * 优点：将 Controller 层的异常和数据校验的异常进行统一处理，减少模板代码，减少编码量，提升扩展性和可维护性。
 * 缺点：只能处理 Controller 层未捕获（往外抛）的异常，对于 Interceptor（拦截器）层的异常，Spring 框架层的异常，就无能为力了
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    private static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理自定义的异常: SystemException
     */
    @ExceptionHandler(SystemException.class)
    @ResponseBody
    public String customHandler(SystemException e) {
        e.printStackTrace();
        logger.error(e.getMessage(), e);
        return e.getMessage();
    }

    /**
     * 处理所有 Controller 层抛出的 Api异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ApiExceptionUtil.class)
    @ResponseBody
    public String apiException(ApiExceptionUtil e) {
        logger.error(e.getMessage(), e);
        return e.getMessage();
    }

    /**
     * @param ex
     * @param request
     * @param response
     * @return
     * @ExceptionHandler 注解中未声明要处理的异常类型，则默认为参数列表中的异常类型
     */
    @ExceptionHandler
    public ApiExceptionUtil processException(Exception ex, HttpServletRequest request, HttpServletResponse response) {
        if (ex instanceof ApiExceptionUtil) {
            if (ex.getCause() != null) {
                logger.error("ApiException occurred!", ex);
            } else {
                logger.error(String.format("ApiException occurred! %s", ex.getMessage()));
            }
            return new ApiExceptionUtil(((ApiExceptionUtil) ex).getErrorCode(), ex.getMessage());
        } else {
            logger.error("Exception occurred!", ex);
            return new ApiExceptionUtil(((ApiExceptionUtil) ex).getErrorCode(), ex.getMessage());
        }
    }
}
